#ifndef BUSINESSLOGICTEST_HPP
#define BUSINESSLOGICTEST_HPP

#include <gtest/gtest.h>
#include "ObjectModel.h"
#include "BusinessLogicController.h"
#include "Helpers.h"

class BusinessLogicTest : public ::testing::Test
{
protected:
  BusinessLogicTest()
  {
    m_model.committees().insert(Committee("1", "For a better good"));
    m_model.committees().insert(Committee("2", "To send all Death Eaters to Azkaban"));

    m_model.councilMembers().insert(CouncilMember("1", "Albus Dumbledore",
      "Hogwarts School of Magic and Wizardy", "Use floo network"));
    m_model.councilMembers().insert(CouncilMember("2", "Gellert Grindelwald",
      "Durmstrang School", "Nobody knows"));
    m_model.councilMembers().insert(CouncilMember("3", "Aberfoth Dumbledore",
      "Hogsmeade willage", "Use mirror fragment"));
    m_model.councilMembers().insert(CouncilMember("4", "Barty Crouch",
      "Somewhere hear London", "Call the Ministry"));
    m_model.councilMembers().insert(CouncilMember("5", "Harry Potter",
      "Privet Drive 4, Little Whinging", "+555555555"));
  
    m_model.membershipHistory().insert(MembershipHistory("1", "1", "1", makeTime(1999, 6, 1), static_cast<time_t>(0)));

    m_model.membershipHistory().insert(MembershipHistory("2", "2", "1", makeTime(1999, 6, 1), static_cast<time_t>(0)));
    m_model.membershipHistory().insert(MembershipHistory("3", "3", "1", makeTime(1999, 6, 1), makeTime(2010, 6, 3)));

    m_model.membershipHistory().insert(MembershipHistory("4", "3", "2", makeTime(2010, 6, 3), static_cast<time_t>(0)));
    m_model.membershipHistory().insert(MembershipHistory("5", "4", "2", makeTime(2009, 6, 1), static_cast<time_t>(0)));
    m_model.membershipHistory().insert(MembershipHistory("6", "4", "1", makeTime(2009, 6, 1), makeTime(2010, 6, 3)));
    m_model.membershipHistory().insert(MembershipHistory("7", "1", "2", makeTime(1999, 6, 1), static_cast<time_t>(0)));

	  m_model.chairmanshipHistory().insert(ChairmanshipHistory("1", "1", "1", makeTime(2009, 6, 1), makeTime(2009, 7, 1)));
	  m_model.chairmanshipHistory().insert(ChairmanshipHistory("2", "1", "2", makeTime(2009, 7, 1), static_cast<time_t>(0)));
	  m_model.chairmanshipHistory().insert(ChairmanshipHistory("3", "2", "1", makeTime(2009, 7, 1), static_cast<time_t>(0)));

	  //breaking the business logic in order to test time queries
	  m_model.chairmanshipHistory().insert(ChairmanshipHistory("4", "2", "1", makeTime(1999, 11, 24), makeTime(2000, 11, 23)));
	  m_model.chairmanshipHistory().insert(ChairmanshipHistory("5", "3", "1", makeTime(2000, 11, 24), makeTime(2002, 11, 25)));

    //sessions
    m_model.sessions().insert(Session("1", "1", makeTime(2000, 1, 15)));
    m_model.sessions().insert(Session("2", "1", makeTime(2000, 2, 15)));
    m_model.sessions().insert(Session("3", "1", makeTime(2000, 3, 15)));

    m_model.sessionPresence().insert(SessionPresence("1", "1", "1"));
    m_model.sessionPresence().insert(SessionPresence("2", "1", "2"));
    m_model.sessionPresence().insert(SessionPresence("3", "1", "3"));
    m_model.sessionPresence().insert(SessionPresence("4", "2", "1"));
    m_model.sessionPresence().insert(SessionPresence("5", "2", "2"));
    m_model.sessionPresence().insert(SessionPresence("6", "3", "1"));

    m_model.serialize("../../data");
    m_model.clear();
    m_model.deserialize("../../data");
  }

  ObjectModel &model() { return m_model; }
private:
  ObjectModel m_model;
};

TEST_F(BusinessLogicTest, ShouldReturn2And0) {
  BusinessLogicController controller(model());
  int first = controller.getSessionCount(*model().committees().committeeById("1"),makeTime(2000,1,15),makeTime(2000,3,14));
  int second = controller.getSessionCount(*model().committees().committeeById("1"),makeTime(2000,1,1),makeTime(2000,1,14));

  ASSERT_EQ(2,first);
  ASSERT_EQ(0,second);
}

TEST_F(BusinessLogicTest, ShouldReturn2CommitteesFor4thMember) 
{
  BusinessLogicController controller(model());
  std::vector<Committee> committees = controller.committeesByMember(*model().councilMembers().memberById("4"));

  ASSERT_EQ(2, committees.size());
   
  ASSERT_EQ(*model().committees().committeeById("2") , committees[0]);
  ASSERT_EQ(*model().committees().committeeById("1") , committees[1]);
}


TEST_F(BusinessLogicTest, ShouldReturn4Dates) 
{
  BusinessLogicController controller(model());
  std::vector<time_t> members = controller.chairmenEntryDatesByCommittee(*model().committees().committeeById("1"));

  ASSERT_EQ(4, members.size());
   
  ASSERT_EQ(model().chairmanshipHistory().historyById("1")->entryDate() , members[0]);
  ASSERT_EQ(model().chairmanshipHistory().historyById("3")->entryDate() , members[1]);
  ASSERT_EQ(model().chairmanshipHistory().historyById("4")->entryDate() , members[2]);
  ASSERT_EQ(model().chairmanshipHistory().historyById("5")->entryDate() , members[3]);

}

TEST_F(BusinessLogicTest, ShouldReturnOnlyOneMemberForTheFirstCommittee)
{
  BusinessLogicController controller(model());
  std::vector<CouncilMember> members = controller.getLatest10YearsChairmen(*model().committees().committeeById("1"));

  ASSERT_EQ(2, members.size());

  ASSERT_EQ(*model().councilMembers().memberById("1"), members[0]);
  ASSERT_EQ(*model().councilMembers().memberById("3"), members[1]);
}

TEST_F(BusinessLogicTest, ShouldReturnTwoMembersWhoIsChairmen) 
{
	BusinessLogicController controller(model());
	CouncilMember member_one = controller.getCurrentCommetteeChairmanship(*model().committees().committeeById("1"));

	ASSERT_EQ(*model().councilMembers().memberById("2"), member_one);

	CouncilMember member_two = controller.getCurrentCommetteeChairmanship(*model().committees().committeeById("2"));
	ASSERT_EQ(*model().councilMembers().memberById("1"), member_two);
}

TEST_F(BusinessLogicTest, ShouldFetchTwoMembersForTheFirstCommittee)
{
  BusinessLogicController controller(model());
  std::vector<CouncilMember> members = controller.currentCommitteeMembers(*model().committees().committeeById("1"));

  ASSERT_EQ(2, members.size());

  ASSERT_EQ(*model().councilMembers().memberById("1"), members[0]);
  ASSERT_EQ(*model().councilMembers().memberById("2"), members[1]);
}

TEST_F(BusinessLogicTest, ShouldMakeListOfTwoCommittees)
{
  const std::string expectedResult = 
    "1|For a better good\n2|To send all Death Eaters to Azkaban\n";

  ASSERT_EQ(expectedResult, model().committees().toString());
}

TEST_F(BusinessLogicTest, ShouldMakeListOfFiveMembers)
{
  const std::string expectedResult = 
    std::string("1|Albus Dumbledore|Hogwarts School of Magic and Wizardy|Use floo network\n") +
    std::string("2|Gellert Grindelwald|Durmstrang School|Nobody knows\n") +
    std::string("3|Aberfoth Dumbledore|Hogsmeade willage|Use mirror fragment\n") +
    std::string("4|Barty Crouch|Somewhere hear London|Call the Ministry\n") +
    std::string("5|Harry Potter|Privet Drive 4, Little Whinging|+555555555\n");

  ASSERT_EQ(expectedResult, model().councilMembers().toString());
}

TEST_F(BusinessLogicTest, ShouldAddCommitteeWithGivenChairman)
{
  const std::string expectedCommitteeList =
    std::string("1|For a better good\n") +
    std::string("2|To send all Death Eaters to Azkaban\n") +
    std::string("3|To destroy all horcruxes\n");

  BusinessLogicController controller(model());
  const std::string committeeId = controller.addCommittee("To destroy all horcruxes", "5");

  ASSERT_EQ("3", committeeId);
  ASSERT_EQ(expectedCommitteeList, model().committees().toString());
  CouncilMember chairman = controller.getCurrentCommetteeChairmanship(*model().committees().committeeById("3"));
  ASSERT_EQ(*model().councilMembers().memberById("5"), chairman);
}

TEST_F(BusinessLogicTest, ShouldReturnListOfMembersWithAbsenceCount)
{
  const std::string expectedList =
    std::string("Albus Dumbledore was absent 0 times\n") +
    std::string("Gellert Grindelwald was absent 1 times\n") +
    std::string("Aberfoth Dumbledore was absent 2 times\n");

  BusinessLogicController controller(model());
  std::string receivedList = 
    controller.listOfAbsence(*model().committees().committeeById("1"), makeTime(2000, 1, 1), makeTime(2000, 4, 1));
  
  ASSERT_EQ(expectedList, receivedList);
}

TEST_F(BusinessLogicTest, AddedSessionShoudIncreaseRecordCountExpectedly)
{
  BusinessLogicController controller(model());
  const Committee *committee = model().committees().committeeById("1");
  std::vector<CouncilMember> members = controller.currentCommitteeMembers(*committee);
 
  std::string newSessionId = controller.addSession(time(0), *committee, members);
  
  ASSERT_EQ("4", newSessionId);
  ASSERT_EQ(4, model().sessions().size());
  ASSERT_EQ(8, model().sessionPresence().size());
}

#endif // BUSINESSLOGICTEST_HPP